﻿using System;
using System.Globalization;
using System.Text;

namespace SpectrumAnalyser.Controls.Wpf.Helpers
{
    public enum ScalingFactor
    {
        None,
        Thousand,
        Million,
        Billion
    }

    public class NumberScalingFormatter : IFormatProvider, ICustomFormatter
    {
        private readonly CultureInfo _underlyingCulture;
        private ScalingFactor _scalingFactor = ScalingFactor.None;

        public NumberScalingFormatter(CultureInfo underlyingCulture)
        {
            if (underlyingCulture == null)
            {
                throw new ArgumentNullException();
            }
            _underlyingCulture = underlyingCulture;
        }

        public ScalingFactor Factor
        {
            get { return _scalingFactor; }
        }

        public CultureInfo Culture
        {
            get { return _underlyingCulture; }
        }


        #region IFormatProvider Members

        public object GetFormat(Type formatType)
        {
            return formatType == typeof (ICustomFormatter) ? this : this._underlyingCulture.GetFormat(formatType);
        }

        #endregion

        #region ICustomFormatter Members

        private int GetUnderlyingThousandScalingFactor()
        {
            var underlyingThousandScalingFactor = 0;

            switch (_scalingFactor)
            {
                case ScalingFactor.None:
                    underlyingThousandScalingFactor = 0;
                    break;

                case ScalingFactor.Thousand:
                    underlyingThousandScalingFactor = 1;
                    break;

                case ScalingFactor.Million:
                    underlyingThousandScalingFactor = 2;
                    break;

                case ScalingFactor.Billion:
                    underlyingThousandScalingFactor = 3;
                    break;
            }
            return underlyingThousandScalingFactor;
        }

        private string GetScalingPostfix()
        {
            switch (_scalingFactor)
            {
                case ScalingFactor.Thousand:
                    return "K";
                    break;

                case ScalingFactor.Million:
                    return "M";
                    break;

                case ScalingFactor.Billion:
                    return "B";
                    break;
                default:
                    return string.Empty;
            }
        }

        private void CaseScaleFactor(double d)
        {
            d = Math.Abs(d);
            if (d < 1000)
            {
                _scalingFactor = ScalingFactor.None;
            }
            else
            {
                if (d < 1000000)
                {
                    _scalingFactor = ScalingFactor.Thousand;
                }
                else
                {
                    this._scalingFactor = d < 1000000000 ? ScalingFactor.Million : ScalingFactor.Billion;
                }
            }
        }

        private object Scale(object arg)
        {
            object scaledValue = null;

            if (arg == null)
            {
            }
            else
            {
                try
                {
                    double convertedValue = Convert.ToDouble(arg);
                    if (!double.IsNaN(convertedValue))
                    {
                        CaseScaleFactor(convertedValue);
                        var underlyingThousandScalingFactor = GetUnderlyingThousandScalingFactor();
                        scaledValue = Math.Pow(10, underlyingThousandScalingFactor*-3)*convertedValue;
                    }
                    else
                    {
                        return arg;
                    }
                }
                catch (InvalidCastException)
                {
                    return arg;
                }
            }
            return scaledValue;
        }

        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            var formattableString = new StringBuilder(format == string.Empty ? "{0:0.0}{1}" : format);

            return string.Format(_underlyingCulture, formattableString.ToString(), Scale(arg), GetScalingPostfix());
        }

        #endregion
    }
}

